package com.sheepshead.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.sheepshead.enums.CardEnum;
import com.sheepshead.enums.SuitEnum;
import com.sheepshead.models.Card;
import com.sheepshead.models.Player;

public class CommonUtil {

	private static final int POINT_VALUE_TO_PICK_ON = 10;

	private static final Logger logger = Logger.getLogger(CommonUtil.class);
	private static final BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 
	private static String in;
	
	public static List<Card> shuffleCards()
	{
		List<Card> deck = createDeck();
		deck = doShuffle(deck);
		return deck;
	}

	private static List<Card> doShuffle(List<Card> deck) {
		Collections.shuffle(deck);
		return deck;
	}

	private static List<Card> createDeck() {
		List<Card> deck = new ArrayList<Card>();
		for(SuitEnum suit : SuitEnum.values())
		{
			for(CardEnum card : CardEnum.values())
			{
				Card newCard = new Card(card, suit);
				deck.add(newCard);
			}
		}
		return deck;
	}

	public static void dealCards(List<Card> deck, List<Player> players, List<Card> blind) {
		boolean blindDealt = false;
		while(!deck.isEmpty())
		{
			for(Player player : players)
			{
				for(int i=0; i<3; i++)
				{
					deck.get(i).setBelongsTo(player.getPosition());
					player.getHand().add(deck.get(i));					
				}
				deck.removeAll(player.getHand());
			}
			if(!blindDealt)
			{
				for(int i=0; i<2; i++)
				{
					blind.add(deck.get(i));
				}
				deck.removeAll(blind);
				blindDealt = true;
			}
		}
	}

	public static void initializePlayers(List<Player> players) {
		for(int i = 0; i<5; i++)
		{
			players.add(new Player(i));
		}
		for(Player player : players)
		{
			player.setHand(new ArrayList<Card>());
		}
	}

	public static boolean chooseBlind(List<Player> players, List<Card> blind) {
		boolean playerChose = false;
		boolean doneInput = false;
		String in;
		List<Card> discard = new ArrayList<Card>();
		for(Player player : players)
		{
			if(player.getPosition() == 0)
			{
				try{
					while(!doneInput)
					{
						player.printHand();
						System.out.print("Pick? [Y/N]: ");
						in = input.readLine();
						logger.debug(in + "\n");
						if(in.toLowerCase().equals("y"))
						{
							player.getHand().addAll(blind);
							discard = doDiscard(player);
							player.getTricks().addAll(discard);
							playerChose = true;
						}
						else if(!in.toLowerCase().equals("n"))
						{
							System.out.println("Could not recognize input.");
						}
						else
						{
							doneInput = true;
							playerChose = false;
						}
					}
				}
				catch(IOException e)
				{
					logger.error(e);
				}
			}
			if(player.getHandPointValue() >= POINT_VALUE_TO_PICK_ON && !playerChose)
			{
				player.setPicked(true);
				player.getHand().addAll(blind);
				player.getTricks().addAll(player.chooseDiscards());
				return true;
			}
			else if(playerChose)
			{
				askForCalledSuit(player, discard);
				player.getHand().removeAll(discard);
				return true;
			}
		}
		return false;
	}

	private static void askForCalledSuit(Player player, List<Card> discard) {
		Map<SuitEnum, List<Card>> possibleCalls = new HashMap<SuitEnum, List<Card>>();
		int counter = 0;
		boolean aloneValid = false;
		boolean suitValid = false;
		try{
			while(!aloneValid)
			{
				System.out.print("Going Alone? [Y/N]: ");
				in = input.readLine();
				if(in.toLowerCase().equals("y"))
				{
					player.setAlone(true);
					aloneValid = true;
				}
				else if(in.toLowerCase().equals("n"))
				{
					aloneValid = true;
					possibleCalls = checkPossibleSuits(player, possibleCalls);
					System.out.println("Possible Calls:\n--------------");
					for(SuitEnum suit : possibleCalls.keySet())
					{
						++counter;
						System.out.print(counter + ". " + suit + ": ");
						for(int i = 0; i < possibleCalls.get(suit).size(); i++)
						{
							System.out.print(possibleCalls.get(suit).get(i).getCardName());
							if(i<possibleCalls.get(suit).size()-1)
							{
								System.out.print(", ");
							}
							else
							{
								System.out.print("\n");
							}
						}
					}
					System.out.print("Discards: ");
					for(int i=0; i<discard.size(); i++)
					{
						System.out.print(discard.get(i).getCardName());
						if(i==discard.size()-1)
						{
							System.out.print("\n");
						}
						else
						{
							System.out.print(", ");
						}
					}
					while(!suitValid)
					{
						System.out.print("Choose [1-" + possibleCalls.keySet().size() + "]: ");
						in = input.readLine();
						if(Integer.parseInt(in) <= counter && Integer.parseInt(in) > 0)
						{
							suitValid = true;
							int i = 1;
							for(SuitEnum suit : possibleCalls.keySet())
							{
								if(i == Integer.parseInt(in))
								{
									player.setCalledSuit(suit);
									logger.debug("Player chose: " + suit + "\n");
									break;
								}
								++i;
							}
						}
					}
				}
				else
				{
					System.out.print("Incorrect input.");
				}
			}
		}
		catch(Exception e)
		{
			logger.error(e);
		}
	}

	private static Map<SuitEnum, List<Card>> checkPossibleSuits(Player player, Map<SuitEnum, List<Card>> possibleCalls) {
		for(Card card : player.getHand())
		{
			if(!card.isTrump() && !card.getValue().equals(CardEnum.ACE))
			{
				
				if(possibleCalls.get(card.getSuit()) == null)
				{
					List<Card> calls = new ArrayList<Card>();
					calls.add(card);
					possibleCalls.put(card.getSuit(), calls);
				}
				else
				{
					List<Card> calls = possibleCalls.get(card.getSuit());
					calls.add(card);
					possibleCalls.put(card.getSuit(), calls);
				}
			}
		}
		return possibleCalls;
	}

	private static List<Card> doDiscard(Player player) {
		int numDiscarded = 0;
		List<Card> discards = new ArrayList<Card>();
		boolean inputCorrect=false;
		while(numDiscarded < 2)
		{
			inputCorrect = false;
			try {
				while(!inputCorrect)
				{
					player.printHand();
					System.out.print("Choose discard [1-" + player.getHand().size() + "]: ");
					in = input.readLine();
					if(Integer.parseInt(in) <= player.getHand().size() || Integer.parseInt(in) > 0)
					{
						inputCorrect = true;
						discards.add(player.getHand().get(Integer.parseInt(in)-1));
						player.getHand().remove(Integer.parseInt(in)-1);
						numDiscarded++;
					}
				}
			} catch (IOException e) {
				logger.error(e);
			}
		}
		player.printHand();
		return discards;
	}

	public static void setPartner(List<Player> players) {
		Player picker = new Player(0);
		boolean partnerFound = false;
		for(Player player : players)
		{
			if(player.isPicked() && !player.isAlone())
			{
				picker = player;
				if(logger.isDebugEnabled())
				{
					logger.debug("Picker is Player " + picker.getPosition() + ".\n");
				}
				break;
			}
		}
		for(Player player : players)
		{
			for(Card card : player.getHand())
			{
				if(card.getSuit().equals(picker.getCalledSuit()) && card.getValue().equals(CardEnum.ACE))
				{
					if(logger.isDebugEnabled())
					{
						logger.debug("Partner is Player " + player.getPosition() + ".\n");
					}
					player.setPartner(true);
					partnerFound = true;
					break;
				}
			}
			if(partnerFound)
			{
				break;
			}
		}
	}

	public static int calculateTrickWinner(List<Card> currentPile) {
		
		return 0;
	}
}
